from fastapi import FastAPI, Request, Depends, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from sqlalchemy.orm import Session
import time

import os
from dotenv import load_dotenv
from contextlib import asynccontextmanager

# Load .env from server folder so DATABASE_URL (if set) is available
load_dotenv(dotenv_path=os.path.join(os.path.dirname(__file__), '..', '.env'))

from . import schemas
from .models.database import engine, Base, get_db
from .models import models


@asynccontextmanager
async def lifespan(app: FastAPI):
    """Lifespan handler: create DB tables on application startup.

    FastAPI's `@app.on_event("startup")` decorator is deprecated in
    newer versions; using a lifespan context manager avoids deprecation
    warnings and is the recommended pattern.
    """
    # create tables before the app starts serving requests
    Base.metadata.create_all(bind=engine)
    try:
        yield
    finally:
        # nothing to clean up for now, but placeholder for future shutdown tasks
        pass


app = FastAPI(title="AutoBuild API", lifespan=lifespan)

# Allow Vite dev server origin during development
origins = [
    "http://localhost:5173",
    "http://127.0.0.1:5173",
]

app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)


@app.middleware("http")
async def log_requests(request: Request, call_next):
    start = time.time()
    print(f"--> {request.method} {request.url.path}")
    response = await call_next(request)
    duration_ms = (time.time() - start) * 1000
    print(
        f"<-- {request.method} {request.url.path} {response.status_code} {duration_ms:.1f}ms"
    )
    return response


@app.get("/api/hello")
def read_root():
    print("hello world")
    return {"message": "this is return"}


@app.get("/api/goodbye")
def read_goodbye():
    return {"message": "Goodbye from FastAPI"}


@app.get("/api/test")
def read_test():
    return {"message": "This is a test endpoint"}

# Note: table creation is performed explicitly by deploy scripts or tests,
# but we also ensure tables exist at application startup via the lifespan
# handler above. This avoids creating tables at import-time which can cause
# issues during test isolation or module reloads.


@app.post("/api/items", response_model=schemas.ItemRead)
def create_item(item: schemas.ItemCreate, db: Session = Depends(get_db)):
    db_item = models.Item(title=item.title, description=item.description)
    db.add(db_item)
    db.commit()
    db.refresh(db_item)
    return db_item


@app.get("/api/items/{item_id}", response_model=schemas.ItemRead)
def read_item(item_id: int, db: Session = Depends(get_db)):
    db_item = db.query(models.Item).filter(models.Item.id == item_id).first()
    if not db_item:
        raise HTTPException(status_code=404, detail="Item not found")
    return db_item


@app.get("/api/items")
def list_items(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
    items = db.query(models.Item).offset(skip).limit(limit).all()
    return items


@app.put("/api/items/{item_id}", response_model=schemas.ItemRead)
def update_item(item_id: int, item: schemas.ItemCreate, db: Session = Depends(get_db)):
    db_item = db.query(models.Item).filter(models.Item.id == item_id).first()
    if not db_item:
        raise HTTPException(status_code=404, detail="Item not found")
    db_item.title = item.title
    db_item.description = item.description
    db.add(db_item)
    db.commit()
    db.refresh(db_item)
    return db_item


@app.delete("/api/items/{item_id}")
def delete_item(item_id: int, db: Session = Depends(get_db)):
    db_item = db.query(models.Item).filter(models.Item.id == item_id).first()
    if not db_item:
        raise HTTPException(status_code=404, detail="Item not found")
    db.delete(db_item)
    db.commit()
    return {"ok": True}
